package com.zxmr.webclient.upload;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.multipart.MultipartFile;

import com.zxmr.domain.account.User;
import com.zxmr.domain.file.File;
import com.zxmr.domain.service.ResourceService;
import com.zxmr.util.ResourceManager;
import com.zxmr.util.Utils;
import com.zxmr.webclient.domain.service.SupportFileFormatService;

public class DefaultUploader extends Uploader{

	static Map<String,Set<String>> supportFormat = new HashMap<String,Set<String>>();
	String folderType = "main";
	
	@Override
	public File upload(MultipartFile cfile,HttpServletRequest request) throws UploadException {
		
		validateInput(cfile,request);
		
		User user = (User)request.getSession().getAttribute("user");
		
        String rootDestnation = getRootDestnation(request);
        String destnationFolder = getDestnationFolder(user);
        String destnationFileName = getDestnationFileName(cfile.getOriginalFilename());
        
		File file = insertToDB(user,cfile.getOriginalFilename(),destnationFolder+destnationFileName);
        
        FlushToFolder(cfile, rootDestnation + destnationFolder,destnationFileName);
        
        return file;
	}

	private void FlushToFolder(MultipartFile cfile, String destFolder,String destFileName)
			throws UploadException {
		try {
				java.io.File f = new java.io.File(destFolder);
		        f.mkdirs();
		        destFolder += destFileName;
       	 		SaveFileFromInputStream(cfile.getInputStream(),destFolder);
		} catch(Exception e)
		{
			e.printStackTrace();
			throw new UploadException("internal error");
		}
	}

	/**
	 * there must be '/' in the head and tail
	 * @param user
	 * @return
	 */
	public String getDestnationFolder(User user)
	{
		SimpleDateFormat dateformat1=new SimpleDateFormat("yyyy-MM-dd");
        String timestamp = dateformat1.format(new Date());
        return "/"+user.getCompany()+"/temp/"+timestamp+"/";
	}
	public String getDestnationFileName(String orign)
	{
		return folderType+"_"+System.nanoTime()+"_"+orign;
	}
	
	public void validateInput(MultipartFile cfile,HttpServletRequest request)throws UploadException
	{
		String format = getFileFormat(cfile.getOriginalFilename());
		validateFormat(format);
	}
	public File insertToDB(User user,String name,String url)throws UploadException
	{
		File file = new com.zxmr.domain.file.File();
		
		file.setCompany(user.getCompany());
		file.setCreateTime(Utils.getCurrentTime());
		file.setOwner(user.getName());
		file.setName(name);
		file.setUrl(url);
		
		ResourceService service = new ResourceService();
		long id = service.addFile(file);
		
		if(id <= 0)throw new UploadException("db insert error");
		file.setId(id);
		
		return file;
	}
	/**
	 * get upload root folder
	 * @param request
	 * @return
	 */
	private String getRootDestnation(HttpServletRequest request)
	{
		return request.getSession().getServletContext().getRealPath("/WEB-INF/upload/");
	}
	
	/**
	 * validate the input format
	 * @param format
	 * @throws UploadException
	 */
	private void validateFormat(String format)throws UploadException {
		Set<String> formats = supportFormat.get(folderType);
		if(formats == null || !formats.contains(format.toLowerCase()))
				throw new UploadException(ResourceManager.getInstance().getMessage("com.client.file.format", String.valueOf(formats)));
	}

	/**
	 * this method used to init support format
	 */
	public static void initSupportFormat(){
		SupportFileFormatService service = new SupportFileFormatService();
		List<String> types = service.queryAllType();
		
		if(types == null || types.isEmpty())return;
		
		for(String type : types)
		{
			List<String> formats = service.queryByType(type);
			Set<String> s = new HashSet<String>();
			s.addAll(formats);
			supportFormat.put(type.toString(), s);
		}
	}
	private String getFileFormat(String filename)
	{
		if(filename == null || filename.isEmpty())return null;
		
		return filename.substring(filename.lastIndexOf('.'), filename.length());
	}
	/**
	 * flush upload stream to destination file
	 * @param stream
	 * @param filename
	 * @throws IOException
	 */
	public void SaveFileFromInputStream(InputStream stream,String filename) throws IOException 
     {      
         FileOutputStream fs=new FileOutputStream(filename); 
         byte[] buffer =new byte[1024*1024]; 
         int byteread = 0; 
         while ((byteread=stream.read(buffer))!=-1) 
         { 
            fs.write(buffer,0,byteread); 
            fs.flush(); 
         } 
         fs.close(); 
         stream.close();      
     }

	public String getFolderType() {
		return folderType;
	}

	public void setFolderType(String folderType) {
		this.folderType = folderType;
	}
	
}
